<?php
require_once  SzSystem::$FRAME_ROOT . '/vendor/facebook/autoload.php';

class ModuleSnsFacebook extends ModuleSns
{
    /**
     * @var Facebook\Entities\SignedRequest $sdk
     */
    protected $sdk;

    /**
     * @var Facebook\FacebookCanvasLoginHelper $fbLoginHelper
     */
    protected $fbLoginHelper;

    /**
     * @see ModuleSns::__construct()
     */
    public function __construct($userId, $platform, $configs)
    {
        /**
         * array(
         *     'appId' => array('key' => 'appId', 'value' => ...),
         *     'appSecret' => array('key' => 'appSecret', 'value' => ...),
         *     'appToken' => array('key' => 'appToken', 'value' => ...),
         *     'payToken' => array('key' => 'payToken', 'value' => ...),
         * )
         *
         * @var array $configs
         */
        parent::__construct($userId, $platform, $configs);

        Facebook\FacebookSession::setDefaultApplication($this->configs['appId']['value'], $this->configs['appSecret']['value']);
        $this->fbLoginHelper = new Facebook\FacebookCanvasLoginHelper();
        $this->sdk = $this->fbLoginHelper->getSignedRequest();
    }

    /**
     * @see ModuleSns::createJsEmbededCode()
     */
    public function createJsEmbeddedCode()
    {
        // if this version is lower then current minimum version，it will auto use current minimum version
        // so we keep use the current minimum version is ok
        return
"<script>
  window.fbAsyncInit = function() {
    FB.init({
      appId      : '" . $this->configs['appId']['value'] . "',
      xfbml      : true,
      oauth      : true,
      version    : 'v2.1'
    });
  };

  (function(d, s, id){
     var js, fjs = d.getElementsByTagName(s)[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement(s); js.id = id;
     js.src = \"//connect.facebook.net/en_US/sdk.js\";
     fjs.parentNode.insertBefore(js, fjs);
   }(document, 'script', 'facebook-jssdk'));
</script>";
    }

    /**
     * @see ModuleSns::getPfToken()
     */
    public function getPfToken()
    {
        return SzParam::getReqParam('signed_request');
    }

    /**
     * @see ModuleSns::getPfSignature()
     */
    public function getPfSignature()
    {
        return null;
    }

    /**
     * Get detailed facebook payment info from facebook.
     *
     * @param string $paymentId could be a numeric payment id OR a payment info url generated from the payment id
     * @param int $retriedTimes max retry time is 3
     * @return array $paymentInfo
     */
    public function getPaymentInfo($paymentId, $retriedTimes = 0)
    {
        $maxRetryTimes = 3;

        $paymentInfoUrl = null;
        if (is_numeric($paymentId)) {
            $paymentInfoUrl = "https://graph.facebook.com/{$paymentId}?access_token={$this->configs['appToken']['value']}&fields=id,user,application,actions,refundable_amount,items,country,request_id,created_time,test,payout_foreign_exchange_rate,tax,tax_country";
            $paymentId = $paymentInfoUrl;
        } else {
            $paymentInfoUrl = $paymentId; // this param called from recursion function call, already converted to an url
        }

        $paymentInfo = null;
        try {
            $paymentInfo = SzUtility::getHttpRequest($paymentInfoUrl);
        } catch (Exception $e) {
            SzLogger::get()->error('[ModuleSnsFacebook] Error in curling facebook payment info: ' . $paymentInfoUrl . ', retried: ' . $retriedTimes);
            if ($retriedTimes < $maxRetryTimes) {
                return $this->getPaymentInfo($paymentId, ($retriedTimes + 1));
            } else {
                return null;
            }
        }
        if (!$paymentInfo) {
            SzLogger::get()->error('[ModuleSnsFacebook] Got empty facebook payment info, paymentId: ' . $paymentId); // empty payment info got
            return null;
        } else {
            return json_decode($paymentInfo, true);
        }
    }

    /**
     * Validate the signature sent from facebook realtime update.
     *
     * @param string $fbInput inputted data from facebook via 'php://input'
     * @param string $signature signature from $_SERVER['HTTP_X_HUB_SIGNATURE']
     * @return boolean true means valid, false means invalid
     */
    public function validateRealtimeUpdateSignature($fbInput, $signature)
    {
        $valid = (hash_hmac('sha1', $fbInput, $this->configs['appSecret']['value']) == $signature);
        if (!$valid) {
            SzLogger::get()->error('[ModuleSnsFacebook] Realtime update: invalid signature');
        }
        return $valid;
    }

    /**
     * Get facebook platform session
     *
     * @return Facebook\FacebookSession $session
     */
    public function getSession()
    {
        return $this->fbLoginHelper->getSession();
    }

    /**
     * Get facebook platform ids for business
     *
     * In Facebook API 2.0, it not possible to get the real platformId directly,
     * and this function can be helpful to find
     *
     * @return Facebook\GraphObject
     * <pre>
     * content inside the GraphObject shall be:
     * {
     *     "data": [
     *         {
     *             "id": "user id in this app",
     *             "app": {
     *                 "name": "facebook app name",
     *                 "namespace": "facebook app namespace link name",
     *                 "id": "app id"
     *             }
     *         },
     *         ...
     *     ],
     *     "paging": {
     *         "cursors": {
     *             "before": "...",
     *             "after": "..."
     *         }
     *     }
     * }
     * </pre>
     */
    public function getPlatformIdForBusiness()
    {
        $request = new Facebook\FacebookRequest($this->fbLoginHelper->getSession(), 'GET', '/me/ids_for_business');
        return $request->execute()->getGraphObject();
    }

    /**
     * @see ModuleSns::initializeOnIndex()
     */
    public function initializeOnIndex()
    {
        return array($this->userId, ModuleSnsConst::PFFB);
    }

    /**
     * @see ModuleSns::getFriends()
     */
    public function getFriends($userId)
    {
        return array();
    }

    /**
     * @see ModuleSns::getPfFriends()
     */
    protected function getPfFriends($userId)
    {
        return array();
    }

    /**
     * @see ModuleSns::preparePfApiEnv()
     */
    protected function preparePfApiEnv()
    {
    }

    /**
     * @see ModuleSns::checkResult()
     */
    protected function checkResult($result)
    {
    }

    /**
     * Get graph def info.
     *
     * @param string $namespace
     * <pre>
     * namespace of the facebook app:
     * https://apps.facebook.com/$namespace
     * </pre>
     * @param string $canvasUrl
     * @param string $objectType
     * <pre>
     * Part of the og:type attribute of facebook open graph:
     * <meta property="og:type" content="{$namespace}:{$objectType}" />
     * </pre>
     * @param string $url
     * <pre>
     * The url can provide the same open graph xml as currently returned one
     * </pre>
     * @param array $graphSetting
     * <pre>
     * array(
     *     title => string,
     *     image => image url string,
     *     description => string
     * )
     * </pre>
     * @return string $info
     */
    public function getGraphInfo($namespace, $canvasUrl, $objectType, $url, $graphSetting)
    {
        $info =
'<!DOCTYPE html>
<html>
<head prefix=
    "og: http://ogp.me/ns#
    fb: http://ogp.me/ns/fb#
    ' . $namespace . ': http://ogp.me/ns/fb/' . $namespace . '#">
   <meta property="fb:app_id"              content="' . $this->configs['appId']['value'] . '" />
   <meta property="og:type"                content="' . $namespace . ':' . $objectType . '" />
   <meta property="og:title"               content="' . $graphSetting['title'] . '" />
   <meta property="og:image"               content="' . $graphSetting['image'] . '" />
   <meta property="og:url"                 content="' . $url . '" />
   <meta property="og:description"         content="' . $graphSetting['description'] . '"/>
</head>
<script type="text/javascript">
    window.location.href = "'. $canvasUrl . '?graph=' . $objectType . '";
</script>
</html>';

        return $info;
    }
}